#ifndef NETWORK_CONTROLLER_H
#define NETWORK_CONTROLLER_H

#include <QMap>
#include <QtNetwork/QtNetwork>
#include <QThread>

#include "RemoteClient.h"
#include "Packet.h"

#include "../logger/Logger.h"

using namespace Logger;

namespace Network {

/**
 * @brief Kontroler połaczeń sieciowych.
 *
 * Zarządza zarówno połączeniami przychodzącymi pełniąc rolę serwera,
 * jak też wszystkimi połączeniami wychodzącymi. Uruchamia serwer.
 * Każde połączenie uruchamiane jest w oddzielnym wątku.
 *
 * Jest to drugi etap na drodze pakietu. Sygnały docierające
 * z połączeń (nowy pakiet, ...) są wyłapywane, obrabiane i przekazywane do dalszej
 * części aplikacji.
 **/
class Controller : public QThread
{

	Q_OBJECT

public:
	/**
	 * Konstruktor. Zapamiętuje numer portu, na którym ma byc uruchomiony serwer.
	 * Fizycznie serwer uruchamiany jest dopiero po wywołaniu metody run.
	 *
	 * @param port port, na którym ma nasłuchiwać serwer
	 **/
	Controller(int port = 52347);

	/**
	 * Podłączenie jako klient do określonego serwera. do połączenia po stronie klienta
	 * zostanie wybrany losowy, wolny port. Połączenie zostanie uruchomione w osobnym wątku.
	 *
	 * @param host_name nazwa serwera bądź adres ip w postaci napisu
	 * @param port numer portu docelowego
	 *
	 * @return wskaźnik na nawiązane połączenie
	 */
	//RemoteClient * connectToHostByIp(QHostAddress addr, int port);
	RemoteClient * connectToHost(QString host_name, int port, int id = -1);


	/**
	 * Kończy działanie wątku serwera
	 **/
	void stop();

	/**
	 * Wysyła pakiet do wszystkich podłączonych klientów
	 *
	 * @param packet pakiet do wysłania
	 **/
	void sendToAll(Packet * packet);

	/**
	 * Wyszukanie połączenia nawiązanego z danym adresem ip
	 **/
	RemoteClient * getOutgoingByIp(int ip);
	RemoteClient * getOutgoingById(int id);

	RemoteClient * getIncomingById(int id);

	RemoteClient * connectToHostByIp(QHostAddress addr, int port, int id = -1);

	int listeningAtPort() {
		return tcpServer->serverPort();
	}

private:
	/**
	 * Metoda wywoływana automatycznie po uruchomieniu wątku.
	 * Uruchamia serwer oraz rozpoczyna działanie pętli komunikatów
	 * dla tego wątku.
	 **/
	void run();

	/// serwer TCP (nasłuchuje na podanym porcie)
	QTcpServer *tcpServer;

	/// lista podłączonych klientów
	QMap <int, RemoteClient*> clients_;

	/// lista połączeń wychodzących
	QMap <int, RemoteClient*> outgoing_;

	/// port, na którym będzie nasłuchiwał serwer
	int port_;

	/// numer kolejnego klienta
	int next_id_;

	/// flaga kontrolująca działanie wątki serwera
	volatile bool active_;

	/// wątek nadrzędny
	QThread * mainThread;

signals:
	/**
	 * Z sieci odebrany został nowy pakiet
	 *
	 * @param client wskazanie na klienta, który odebrał pakiet
	 **/
	void newPacket(RemoteClient * client);

	/**
	 * Do serwera podłączył się nowy klient
	 *
	 * @param client wskazanie na podłączonego klienta
	 **/
	void newClient(RemoteClient * client);

	/**
	 * Klient zdechł
	 **/
	void clientDied(RemoteClient * client);

	/**
	 * Komunikat wysyłany do systemu logującego zdarzenia.
	 *
	 * @param msg treść komunikatu
	 * @param type typ komunikatu
	 **/
	void newMsg(QString msg, int type);

public slots:
	/**
	 * Połączenie z klientem zostało zerwane
	 **/
	void onClientDied(RemoteClient * client);

	/**
	 * Usunięcie z listy danego klienta
	 **/
	void removeClient(RemoteClient * client);

private slots:
	/**
	 * Podłączył się nowy klient
	 **/
	void onNewConnection();

	/**
	 * Dany klient odebrał z sieci pakiet.
	 *
	 * @param client klient, który odebrał pakiet
	 **/
	void onNewPacket(RemoteClient * client);

	/**
	 * Zakończenie działania kontrolera. Wszystkie aktywne
	 * połaczenia są zamykane a wątki z nimi związane
	 * zostają zakończone.
	 **/
	void onFinished();

};

} // namespace Network

#endif // NETWORK_CONTROLLER_H
